package com.cts.aspect;

import com.cts.annotation.OperationLogger;
import com.cts.entity.OperationLog;
import com.cts.model.dto.LoginUser;
import com.cts.service.OperationLogService;
import com.cts.util.*;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * @projectName: CBlog
 * @package: com.cts.aspect
 * @className: OperationLogAspect
 * @author: chentongsheng
 * @description: TODO
 * @date: 2023/4/4 23:37
 * @version: 1.0
 */
@Component
@Aspect
@Slf4j
public class OperationLogAspect {

    @Autowired
    OperationLogService operationLogService;

    @Autowired
    RedisUtils redisUtils;

    ThreadLocal<Long> currentTime = new ThreadLocal<>();

    @Pointcut("@annotation(operationLogger)")
    public void logPointcut(OperationLogger operationLogger) {
    }

    @Around("logPointcut(operationLogger)")
    public Object logAround(ProceedingJoinPoint joinPoint, OperationLogger operationLogger) throws Throwable {
        currentTime.set(System.currentTimeMillis());
        Object result = joinPoint.proceed();
        int times = (int) (System.currentTimeMillis() - currentTime.get());
        currentTime.remove();
        OperationLog operationLog = handleLog(joinPoint, operationLogger, times);
        log.info("开始写入操作日志");
        operationLogService.save(operationLog);
        log.info("结束写入操作日志");
        return result;
    }

    private OperationLog handleLog(ProceedingJoinPoint joinPoint, OperationLogger operationLogger, int times) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String userId = JwtUtils.getTokenBody(request.getHeader("Authorization")).getSubject();
        LoginUser loginUser = (LoginUser) redisUtils.get("Login:" + userId);
        String username = loginUser.getUsername();
        String uri = request.getRequestURI();
        String method = request.getMethod();
        String description = operationLogger.value();
        String ip = IpUtils.getIpAddress(request);
        String ipSource = IpUtils.getCityInfo(ip);
        String userAgentHeader = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgent.parseUserAgentString(userAgentHeader);
        String os = userAgent.getOperatingSystem().getName();
        String browser = userAgent.getBrowser().toString();

        OperationLog operationLog = new OperationLog(username, uri, method, description, ip, ipSource, times, userAgentHeader, os, browser);
        Map<String, Object> requestParams = AopUtils.getRequestParams(joinPoint);
        operationLog.setParam(StringUtils.substring(JacksonUtils.writeValueAsString(requestParams), 0, 2000));
        operationLog.setCreateTime(LocalDateTime.now());
        return operationLog;
    }
}
